/*
 * Directory.cpp
 *
 *  Created on: Apr 19, 2011
 *      Author: 
 */

#include "Directory.h"
#include "string.h"
#include <stdio.h>

Directory::Directory(Inode* i) : Datafile(i) {
	entryList = new vector<directoryEntry*>();
	//addFilename(".", i->getInodeNr());
	//addFilename("..", parent);
	parseDirectory();
}

Directory::~Directory() {
	for(vector<directoryEntry*>::iterator it = entryList->begin(); it != entryList->end(); it++) {
		delete (*it);
	}
	entryList->clear();
	delete entryList;
}

bool Directory::compareFilenames(char* name1, char* name2) {
	//cout << "compare " << name1 << " with " << name2 << endl;
	if(strcmp(name1, name2) == 0){
		return true;
	}
	return false;
}

list<string>* Directory::getFilenames() {
	list<string>* filenames = new list<string>();
	for(vector<directoryEntry*>::iterator it = entryList->begin(); it != entryList->end(); it++) {
		if((*it)->getNr()) {
			filenames->push_back((*it)->getName());
		}
	}
	return filenames;
}

bool Directory::addFilename(char* name, ino_x inodeNr) {
	//cout << "trying to add: " << inodeNr << " - " << name << endl;
	for(vector<directoryEntry*>::iterator it = entryList->begin(); it != entryList->end(); it++) {
		if(compareFilenames((*it)->getName(), name)) {
			return false;
		}
	}
	//if the entry doesn't exist, add it
	directoryEntry* entry = new directoryEntry(inodeNr, name);
	entryList->push_back(entry);
	return true;
}

bool Directory::addNewFile(char* name, ino_x inodeNr){
	for(vector<directoryEntry*>::iterator it = entryList->begin(); it != entryList->end(); it++) {
		if(compareFilenames((*it)->getName(), name)) {
			cout << "ALREADY EXISTS" << endl;
			return false;
		}
	}
	directoryEntry* entry = new directoryEntry(inodeNr, name);
	entryList->push_back(entry);
	write(entry);
	return true;
}

void Directory::deleteFilename(char* name) {
	cout << "start delete" << endl;
	cout << "looking for " << name << endl;
	for(vector<directoryEntry*>::iterator it = entryList->begin(); it != entryList->end(); it++) {
		if(compareFilenames((*it)->getName(), name)) {
			cout << "found it" << endl;
			int inr = (*it)->getNr();
			cout << inr << endl;
			entryList->erase(it);
			lseek(0,0);
			for(int i = 0; i < (inode->getSize()/16); i++){
				byte ino[2];
				byte bname[14];
				void * inoArr = &ino;
				read(inoArr, 2);
				//cout << (int) inoArr[0] << " | " << inoArr[1] << endl;
				ino_x inum = formulateNumber(ino);
				//cout << "number: " << inum << endl;
				read(bname, 14);
				char* fname = (char*)formulateName(bname, 14);
				if(inum == inr && ((string)fname).compare(((string)name)) == 0){
					byte empty[2];
					empty[0] = 0;
					empty[1] = 0;
					long blk = inode->getDiskBlockNr((i*16)/DSKBLKSIZ);
					FS::getInstance()->writeInBlock(blk, (i*16)%DSKBLKSIZ, empty, 2);
				}
			}
		}
	}
}

ino_x Directory::getInodeNumber(char* name) {
	for(vector<directoryEntry*>::iterator it = entryList->begin(); it != entryList->end(); it++) {
		if(compareFilenames((*it)->getName(), name)) {
			return (*it)->getNr();
		}
	}
	return 0;
}

ino_x Directory::getInodeNumber() {
	return inode->getInodeNr();
}

void Directory::parseDirectory(){
	//cout << "start parsing..." << endl;
	//cout << "s: " << inode->getSize() << endl;
	for(int i = 0; i < (inode->getSize()/16); i++){
		//cout << "loop" << endl;
		byte ino[2];
		byte bname[14];
		void * inoArr = &ino;
		read(inoArr, 2);
		//cout << (int) inoArr[0] << " | " << inoArr[1] << endl;
		ino_x inum = formulateNumber(ino);
		//cout << "number: " << inum << endl;
		read(bname, 14);
		char* name = (char*)formulateName(bname, 14);
		//cout << "name: " << name << endl;
		if(inum > 0){
			if(addFilename(name, inum) == false){
				//cout << "ERROR ADDING" << endl;
			}
		}
	}
	//cout << "end of directory parsing" << endl;
}

const char* Directory::formulateName(byte* bname, int count){
	string s = "";
	for(int i = 0; i < count; i++){
		if((int)bname[i] != 0){
			s.push_back(bname[i]);
		}else break;
	}
	return s.c_str();
}

ino_x Directory::formulateNumber(byte* bnum){
	ino_x output;
	char* array = (char*) &output;
	int a = 0x12345678;
	unsigned char *c = (unsigned char*)(&a);
	if (*c == 0x78){
		array[0] = bnum[1];
		array[1] = bnum[0];
	}else{
		array[0] = bnum[0];
		array[1] = bnum[1];
	}
	return output;
}

void Directory::print(){
	cout << "DIRECTORY" << endl;
	for(unsigned int i = 0; i < entryList->size(); i++){
		//cout << "loop" << endl;
		ino_x inum = entryList->at(i)->getNr();
		char* name = entryList->at(i)->getName();
		cout << inum << ":  " << name << endl;
		printf("%-14s\n", name);
	}
}

void Directory::write(directoryEntry* entry){
	//zoeken naar een plek met inode nummer 0
	cout << "WRITING ENTRY" << endl;
	iopos = 0;
	for (int i = 0; i < (inode->getSize() / 16); i++) {
		cout << "LOOP" << endl;
		byte ino[2];
		byte bname[14];
		void * inoArr = &ino;
		read(inoArr, 2);
		ino_x inum = formulateNumber(ino);
		read(bname, 14);
		cout << inum << endl;
		if (inum == 0) {
			cout << "FOUND EMPTY SPACE AT " << i << endl;
			byte d[16];
			ino_x newinum = entry->getNr();
			char* newnam = entry->getName();
			cout << "NEWNAM: " << newnam << endl;
			int charlength = ((string)newnam).length();
			byte* ib = (byte*) &newinum;
			const int endian = 1;
			if(( (*(char*)&endian) == 0 )){
				for(int i = 0; i < 2; i++){
					d[i] = ib[i];
				}
				for (int i = 0; i < 14; i++) {
					if (i < charlength) {
						cout << "ADDING CHARACTER: " << newnam[i] << ", number: " << (int) newnam[i] << " at " << i << endl;
						d[i + 2] = newnam[i];
					} else {
						d[i + 2] = 0;
					}
				}
			}else{
				d[0] = ib[1];
				d[1] = ib[0];
				for(int i = 0; i < 14; i++){
					if(i < charlength){
						cout << "ADDING CHARACTER: " << newnam[i] << ", number: " << (int)newnam[i] << " at " << i << endl;
						d[i+2] = newnam[i];
					}else{
						d[i+2] = 0;
					}
				}
			}
			cout << "WRITING ENTRY TO POSITION " << i << endl;
			int blocknr = inode->getDiskBlockNr(i/32);
			FS::getInstance()->writeInBlock(blocknr, (i%32)*16, d, 16);
			inode->setLastModifiedTime();
			break;
		}
	}
}

/*void Directory::printDetail(){
	cout << "DIRECTORY WITH DETAILS" << endl;
	ino_x inums[entryList->size()];
	char* modes[entryList->size()];
	int links[entryList->size()];
	char* owners[entryList->size()];
	int maxName;
	char* groups[entryList->size()];
	int maxGroup;
	int sizes[entryList->size()];
	int maxSize;
	long dates[entryList->size()];
	int maxDate;
	char* names[entryList->size()];
	for(unsigned int i = 0; i < entryList->size(); i++){
		directoryEntry* entry = entryList->at(i);
		inums[i] = entry->getNr();
		names[i] = entry->getName();
		//printf("%10s %4s %10s %10s %10i %20s %14s\n")
	}
}*/
